package com.util;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

/**
 * Created by Administrator on 2016/3/24.
 */
public class ImageDisposeUtil {


    /**
     * 二分法JPG图片质量压缩
     *
     * @param handler   UI线程handler
     * @param bitmapSrc 图片bitmap
     * @param maxSize   图片限制大小
     */
    public static void compressJPEGByQuality(final Handler handler,
                                             final Bitmap bitmapSrc, final int maxSize) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                int low = 0; // 最小压缩率
                int high = 100; // 最大压缩率
                int mid; // 中间数值
                // 最大限制图片的字节数,之所以maxSize-1是为了提高压缩时的查找效率
                int maxSizeByte = (maxSize - 1) * 1024;
                Bitmap bitmap = bitmapSrc;
                ByteArrayOutputStream compressStream = new ByteArrayOutputStream();
                while (low <= high) {
                    if (low == high) {
                        bitmap.compress(Bitmap.CompressFormat.JPEG, low, compressStream);
                        int compressLength = compressStream.toByteArray().length;
                        if (compressLength <= maxSizeByte) { // 压缩成功
                            recycleBitmapAndCloseOutputStream(bitmap, compressStream);
                            sendMessage(handler, compressStream);
                        } else { // 压缩所得图片过大
                            compressStream.reset();
                            if (low - 1 < 0) { //low已经达到最小值,无法再进行压缩
                                recycleBitmapAndCloseOutputStream(bitmap, compressStream);
                                sendMessage(handler, null);
                                return;
                            }
                            // 压缩率-1继续压缩
                            bitmap.compress(Bitmap.CompressFormat.JPEG, --low, compressStream);
                            compressLength = compressStream.toByteArray().length;
                            // 若low-1压缩后仍大于限制图片大小,继续压缩
                            while (low > 0
                                    && compressLength > maxSizeByte) {
                                compressStream.reset();
                                bitmap.compress(Bitmap.CompressFormat.JPEG, --low, compressStream);
                                compressLength = compressStream.toByteArray().length;
                            }
                            if (low >= 0) { // 表示压缩成功
                                recycleBitmapAndCloseOutputStream(bitmap, compressStream);
                                sendMessage(handler, compressStream);
                            } else {
                                recycleBitmapAndCloseOutputStream(bitmap, compressStream);
                                sendMessage(handler, null);
                            }
                        }
                        return;
                    } else if (high - low == 1) {
                        bitmap.compress(Bitmap.CompressFormat.JPEG, high, compressStream);
                        int highLength = compressStream.toByteArray().length;
                        if (highLength <= maxSizeByte) {
                            recycleBitmapAndCloseOutputStream(bitmap, compressStream);
                            sendMessage(handler, compressStream);
                        } else {
                            compressStream.reset();
                            bitmap.compress(Bitmap.CompressFormat.JPEG, low, compressStream);
                            int lowLength = compressStream.toByteArray().length;
                            if (lowLength <= maxSizeByte) {
                                recycleBitmapAndCloseOutputStream(bitmap, compressStream);
                                sendMessage(handler, compressStream);
                            } else {
                                compressStream.reset();
                                if (low - 1 < 0) { //low已经达到最小值,无法再进行压缩
                                    recycleBitmapAndCloseOutputStream(bitmap, compressStream);
                                    sendMessage(handler, null);
                                    return;
                                }
                                // 压缩率-1继续压缩
                                bitmap.compress(Bitmap.CompressFormat.JPEG, --low, compressStream);
                                int compressLength = compressStream.toByteArray().length;
                                // 若low-1压缩后仍大于限制图片大小,继续压缩
                                while (low > 0
                                        && compressLength > maxSizeByte) {
                                    compressStream.reset();
                                    bitmap.compress(Bitmap.CompressFormat.JPEG, --low, compressStream);
                                    compressLength = compressStream.toByteArray().length;
                                }
                                if (low >= 0) { // 表示压缩成功
                                    recycleBitmapAndCloseOutputStream(bitmap, compressStream);
                                    sendMessage(handler, compressStream);
                                } else {
                                    recycleBitmapAndCloseOutputStream(bitmap, compressStream);
                                    sendMessage(handler, null);
                                }
                            }
                        }
                        return;
                    }
                    mid = (low + high) / 2; // 取中间压缩率进行图片压缩
                    bitmap.compress(Bitmap.CompressFormat.JPEG, mid, compressStream);
                    int compressLength = compressStream.toByteArray().length;
                    if (compressLength > maxSizeByte) {// 压缩后的文件超过指定大小
                        high = mid - 1;
                    } else if (compressLength == maxSizeByte) {// 压缩后的文件等于指定大小
                        recycleBitmapAndCloseOutputStream(bitmap, compressStream);
                        sendMessage(handler, compressStream);
                        return;
                    } else {
                        low = mid + 1;
                    }
                    compressStream.reset();// 重置
                }
                Looper.loop();
            }
        }).start();
    }

    //回收Bitmap对象并关闭输出流
    private static void recycleBitmapAndCloseOutputStream(Bitmap bitmap, ByteArrayOutputStream compressStream) {
        if (!bitmap.isRecycled()) {
            bitmap.recycle();
        }
        try {
            compressStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 发送消息给主线程
    private static void sendMessage(Handler handler, ByteArrayOutputStream compressStream) {
        Message msg = new Message();
        msg.setTarget(handler);
        if (compressStream == null) {
            msg.obj = "outOfSize";
            msg.sendToTarget();
            return;
        }
        if (ExternalStorageUtil.isExternalStorageEnable()) {
            String filePath = FileUtil.writeBinaryFile(compressStream.toByteArray(), ExternalStorageUtil.getExternalStoragePath() + "imgCompress" + File.separator + "compress.jpg");
            if (TextUtil.isValidate(filePath)) {
                msg.obj = filePath;
            } else {
                msg.obj = "WriteFileFail";
            }
        } else {
            msg.obj = "ExternalStorageUnable";
        }
        msg.sendToTarget();
    }

    /**
     * JPG图片压缩,先进行比例压缩再进行质量压缩
     *
     * @param handler UI线程handler对象
     * @param imgPath 图片路径
     * @param maxSize 限制大小
     */
    public static void compressJPG(Handler handler, String imgPath, int maxSize) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        //开始读入图片，此时把options.inJustDecodeBounds设置为true，为了只读取Bitmap的部分信息 
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(imgPath, newOpts);//此时返回bm为空  
        newOpts.inSampleSize = calculateInSampleSize(newOpts, ScreenUtil.getScreenWidth(), ScreenUtil.getScreenHeight());
        newOpts.inJustDecodeBounds = false; //此时可以加载bitmap到内存中了
        //重新读入图片，注意此时已经把options.inJustDecodeBounds 设回false了  
        while (true) {
            try {
                bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
                break;
            } catch (Exception e) {//若发生内存溢出,则将压缩比例提升再压缩
                if (bitmap != null && !bitmap.isRecycled()) {
                    bitmap.recycle();
                }
                newOpts.inSampleSize++;
                e.printStackTrace();
            }
        }
        compressJPEGByQuality(handler, bitmap, maxSize);
    }

    /**
     * 以最省内存的方式读取手机存储中的图片
     *
     * @param imagePath 图片路径
     * @return bitmap对象
     */
    public static Bitmap getImageBitmap(String imagePath) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPurgeable = true;
        opt.inInputShareable = true;
        //获取资源图片
        return BitmapFactory.decodeFile(imagePath, opt);
    }

    /**获取bitmap的字节数
     * @param bitmap
     * @return
     */
    public static int getBitmapBytes(Bitmap bitmap) {
        int result;
        if (Build.VERSION.SDK_INT >= 12) {
            result = bitmap.getByteCount();
        } else {
            result = bitmap.getRowBytes() * bitmap.getHeight();
        }

        if (result <= 0) {
            return -1;
        } else {
            return result;
        }
    }

    /**
     * 根据图片信息及手机屏幕分辨率计算缩放比例
     *
     * @param options   图片信息对象
     * @param reqWidth  屏幕宽度
     * @param reqHeight 屏幕高度
     * @return 缩放比例
     */
    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        return inSampleSize;
    }

}
